/**
 * Copyright(c) kyle.
 */
package org.example.tomcat.netty.business;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.example.tomcat.netty.basic.GPRequest;
import org.example.tomcat.netty.basic.GPResponse;
import org.example.tomcat.netty.basic.GPServlet;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 主要的启动类
 *
 * @author kyle
 * @version 1.00.00
 * @since [2020-10-21 10:49]
 * @updateUser [Kyle]
 * @updateRemark [说明本次修改内容]
 * @date [2020-10-21 10:49]
 */
public class GPTomcat {
    private static final Map<String, GPServlet> servletMap = new HashMap<>();
    private final int port = 8080;
    private final Properties webxml = new Properties();

    public static void main(String[] args) {
        new GPTomcat().start();
    }

    private void init() throws Exception {
        String WEB_INF = ".\\src\\main\\java\\org\\example\\tomcat\\netty\\resouce\\";
        FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
        webxml.load(fis);
        for (Object k : webxml.keySet()) {
            String key = k.toString();
            if (key.endsWith(".url")) {
                String servletName = key.replaceAll("\\.url$", "");
                String url = webxml.getProperty(key);
                String className = webxml.getProperty(servletName + ".className");
                GPServlet obj = (GPServlet) Class.forName(className).newInstance();
                servletMap.put(url, obj);
            }
        }
    }

    public void start() {
        try {
            init();

            //boss线程
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            //Worker线程
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap server = new ServerBootstrap();

                server.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(final SocketChannel pSocketChannel) throws Exception {
                                pSocketChannel.pipeline()
                                        .addLast(new HttpResponseEncoder())
                                        .addLast(new HttpRequestDecoder())
                                        .addLast(new GPTomcatHandler());
                            }
                        })
                        //针对主线程的配置，分配线程最大数量，128
                        .option(ChannelOption.SO_BACKLOG, 128)
                        //针对子线程的配置，保持长连接
                        .option(ChannelOption.SO_KEEPALIVE, true);

                //启动服务器
                ChannelFuture f = server.bind(port).sync();
                System.out.println("服务器以启动，监听端口是" + port);
                f.channel().closeFuture().sync();
            } catch (Exception pE) {
                pE.printStackTrace();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class GPTomcatHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
            super.channelRead(ctx, msg);
            if (msg instanceof HttpRequest) {
                System.out.println("接收到请求");
                HttpRequest req = (HttpRequest) msg;

                //转交给我们自己的Request
                GPRequest request = new GPRequest(ctx, req);
                GPResponse response = new GPResponse(ctx, req);
                String url = request.getUrl();

                if (servletMap.containsKey(url)) {
                    servletMap.get(url).service(request, response);
                } else {
                    response.write("404 - not found");
                }
            }
        }
    }
}
